package io.lkt.modules.sys.utils;

import com.alibaba.fastjson.JSON;
import io.lkt.common.utils.AliyunOssClientUtil;
import io.lkt.common.utils.DateUtil;
import io.lkt.modules.dto.Base;
import io.lkt.modules.sys.entity.BArticleInfoEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.StandardCopyOption;
import java.util.UUID;

/**
 * 微信文章工具类
 *
 * @version : V1.0
 * @ClassName: WebSpiderUtil
 * @Description: TODO
 * @Auther: chujiu
 * @Date: 2021/2/26 15:59
 */
@Slf4j
//@RestController
public class WebSpiderUtil {
    private static final String ArticleUrl = "https://mp.weixin.qq.com/s/KO7Z4W5e4rKQTXupa0IJIg";
    private static final String VideoUrl = "https://mp.weixin.qq.com/s/YA5kvH0fTmoYb2qhtmgXgA";
    private static final String AudioUrl = "https://mp.weixin.qq.com/s/SVnN6ko712m7BEjNcgOCKQ";

    public static void main(String[] args) throws IOException {

        String weiXinPageUrl = "https://mp.weixin.qq.com/s/YA5kvH0fTmoYb2qhtmgXgA";
        weiXinPageUrl = ArticleUrl;
        weiXinPageUrl = VideoUrl;
//        weiXinPageUrl = AudioUrl;

        getWeiXinPage(weiXinPageUrl);
    }

    /**
     * 方法描述：微信公众号文章
     *
     * @param weiXinPageUrl
     * @throws IOException
     */
    public static BArticleInfoEntity getWeiXinPage(String weiXinPageUrl) throws IOException {
        if (!StringUtils.isNotBlank(weiXinPageUrl) || !weiXinPageUrl.contains("mp.weixin.qq.com")) {
//            System.out.println(weiXinPageUrl + " 不是微信公众号文章链接");
            return null;
        }

//        System.out.println("是微信公众号文章链接");
        weiXinPageUrl = weiXinPageUrl.trim().replaceAll("\"", "");

        String webContent = getPageString(weiXinPageUrl);
        //替换微信img
        webContent = replaceImgSrcFromDataSrc(webContent);
        webContent = replaceAudioFromMpvoice(webContent);

        Document document = Jsoup.parseBodyFragment(webContent);


        Element ele = document.getElementById("js_content");//当根据id取单个元素的时候
        if (ele == null) {
//            System.out.println("没有匹配id为js_content的元素");
            return null;
        }

//        System.out.println("有匹配id为js_content的元素");
        BArticleInfoEntity bArticleInfo = new BArticleInfoEntity();

        String title = document.select("meta[property=\"og:title\"]").attr("content");
        bArticleInfo.setArticleTitle(title);
//        System.out.println("网页标题为：" + title);

        String desc = document.select("meta[property=\"og:description\"]").attr("content");
        bArticleInfo.setArticleDesc(desc);
//        System.out.println("网页配文为：" + desc);

        String image = document.select("meta[property=\"og:image\"]").attr("content");
        bArticleInfo.setArticleImgUrl(getImg(image));

        Elements elev = document.getElementsByClass("rich_media_content");//当根据类名之类,取多个元素的时候
        if (elev.isEmpty()) { //eles类似于集合,所以用权isEmpty来判断
//            System.out.println("没有class为rich_media_content的元素集合");

            //提取视频元素
            String reg = "url: 'http://mpvideo.qpic.cn/";
            if (document.toString().contains(reg)) {
//                System.out.println("文章类型 =================== 视频文章");

                Document doc = Jsoup.parseBodyFragment("<div id=\"js_content\"><p id=\"js_common_share_desc\">JS_COMMON_SHARE_DESC</p></div>".replace("JS_COMMON_SHARE_DESC", desc));
                doc.attr("style", "max-width: 100%;");

                String videoName = getVideo(weiXinVideoPage(document));
                doc.prepend("<video controls=\"controls\" width=\"800\" height=\"\"> <source src='http://www.viedo.com.cn/movie.mp4' type=\"video/mp4\" /> </video>"
                        .replace("http://www.viedo.com.cn/movie.mp4", videoName));//在div前添加html内容

                bArticleInfo.setArticleContent(doc.toString());
            }
            return bArticleInfo;
        }
//        System.out.println("有class为rich_media_content的元素集合");

        Document htmlDoc = Jsoup.parse(webContent);
        //获取替换后的 iframe
        htmlDoc = weiXinVideoPageIframe(htmlDoc);

        //获取替换后的div
        Element headDiv = htmlDoc.select("div#js_content").first();
        headDiv.attr("style", "max-width: 100%;");

        bArticleInfo.setArticleContent(headDiv.toString());

//        System.out.println("==========: 打印网页内容 :==========");  //打印网页内容
//        System.out.println("==========: 手动分割线 :==========");
//        System.out.println("");
//        System.out.println(headDiv);

        return bArticleInfo;
    }

    /**
     * 根据微信音频文章网页内容获取音频地址
     *
     * @param document 网页内容
     * @return 音频地址
     */
    private static String weiXinAudioPage(Document document) {
        String uri = "http://res.wx.qq.com/voice/getvoice?mediaid=MEDIAID";
        String mediaId = document.select("mpvoice[data-pluginname=\"insertaudio\"]").attr("voice_encode_fileid");
//        System.out.println("mediaId = " + mediaId);
        uri = uri.replace("MEDIAID", mediaId);

        return uri;
    }

    /**
     * 根据微信音频文章网页内容获取视频地址
     * //mp.weixin.qq.com/mp/readtemplate?t=pages/video_player_tmpl&auto=0&vid=wxv_1757392981919121413
     *
     * @param document 网页内容
     * @return 视频地址
     */
    /**
     * 接口一：视频播放的 iframe 原地址
     * 请求方式：GET
     * 参数：vid：微信视频ID
     * http://mp.weixin.qq.com/mp/readtemplate?t=pages/video_player_tmpl&auto=0&vid=wxv_1219759656583774208
     * <p>
     * 接口二：请求视频接口,获取视频 url
     * 请求方式：POST
     * 参数：vid：微信视频ID
     * http://mp.weixin.qq.com/mp/videoplayer?action=get_mp_video_play_url&preview=0&__biz=&mid=&idx=&vid=wxv_1219759656583774208&uin=&key=&pass_ticket=&wxtoken=&appmsg_token=&x5=0&f=json
     *
     * @param document
     * @return
     */
    private static String weiXinVideoPage(Document document) {
        String webContent = document.toString();
        //你想要的内容左右所对应,有空格的注意空格
        String path = "url: 'http://mpvideo.qpic.cn/";
//        System.out.println("字符串中是否包含了 'content' 子字符串? " + webContent.contains(path));

        String vid = "";
        if (webContent.contains("wxv_")) {
            String content = webContent;
            content = content.substring(content.indexOf("wxv_")).substring(0, 30);//截取之后的字符串

            content = content.substring(0, content.indexOf("'"));//截取之前的字符串
//            System.out.println("vid = " + content);
            vid = content;
        }

        String web = "";
        if (webContent.contains(path)) {
            String content = webContent;
            content = content.substring(content.indexOf("url: 'http://mpvideo.qpic.cn/")).replace("url: '", "");//截取之后的字符串
            content = content.substring(0, content.indexOf("video_quality_level: '3' * 1 || 0,"));//截取之前的字符串
            content = content.substring(0, content.indexOf("',"));
//            System.out.println("web = " + content);

            web = content;
        }

        String format_id = "";
        if (webContent.contains(".mp4")) {
            String content = web;
            content = content.substring(content.indexOf(".f")).substring(0, 30).replace(".f", "");//截取之后的字符串
            content = content.substring(0, content.indexOf(".mp4?"));//截取之前的字符串
//            System.out.println("format_id = " + content);

            format_id = content;
        }

        String uri = web + "&vid=" + vid + "&format_id=" + format_id;
        uri = uri.replace("\\x26amp;", "&");

        return uri;
    }

    /**
     * 接口一：视频播放的 iframe 原地址
     * 请求方式：GET
     * 参数：vid：微信视频ID
     * http://mp.weixin.qq.com/mp/readtemplate?t=pages/video_player_tmpl&auto=0&vid=wxv_1219759656583774208
     * <p>
     * 接口二：请求视频接口,获取视频 url
     * 请求方式：POST
     * 参数：vid：微信视频ID
     * http://mp.weixin.qq.com/mp/videoplayer?action=get_mp_video_play_url&preview=0&__biz=&mid=&idx=&vid=wxv_1219759656583774208&uin=&key=&pass_ticket=&wxtoken=&appmsg_token=&x5=0&f=json
     *
     * @param document
     * @return
     */
    private static Document weiXinVideoPageIframe(Document document) throws IOException {
        String url = "http://mp.weixin.qq.com/mp/videoplayer?action=get_mp_video_play_url&preview=0&__biz=&mid=&idx=&vid=WXV_WID&uin=&key=&pass_ticket=&wxtoken=&appmsg_token=&x5=0&f=json";

        Elements nodes = document.select("iframe");
        int nodeLength = nodes.size();
        for (int i = 0; i < nodeLength; i++) {
            Element e = nodes.get(i);

            String dataSrc = e.attr("data-mpvid");

            if (StringUtils.isNotBlank(dataSrc)) {
                String vUrl = url.replace("WXV_WID", dataSrc);
                String body = Jsoup.connect(vUrl).ignoreContentType(true).execute().body().toString();

                //测试 Fastjson 反序列化
                Base base = JSON.parseObject(body, Base.class);
                if (base != null && base.getUrlInfo() != null && base.getUrlInfo().size() > 0 && base.getUrlInfo().get(0).getUrl() != null) {
                    String result = base.getUrlInfo().get(0).getUrl();

                    //获取Video
                    result = getVideo(result);

                    //替换为自己的
                    e.wrap("<video controls=\"controls\" width=\"800\">" +
                            "<source src=\"" + result + "\" type=\"video/mp4\"></source>" +
                            "</video>");
                }
            }
        }
        return document;
    }

    /**
     * 将htmlBody中所有mpvoice标签替换为audio,
     *
     * @param htmlBody
     * @return 返回替换后的内容
     */
    private static String replaceAudioFromMpvoice(String htmlBody) {
        String url = "http://res.wx.qq.com/voice/getvoice?mediaid=MEDIA_ID";

        Document document = Jsoup.parseBodyFragment(htmlBody);

        Elements nodes = document.select("mpvoice");
        int nodeLength = nodes.size();
        for (int i = 0; i < nodeLength; i++) {
            Element e = nodes.get(i);

            String urlID = e.attr("voice_encode_fileid");

            if (StringUtils.isNotBlank(urlID)) {
                String result = url.replace("MEDIA_ID", urlID);
                //替换为自己的
                result = getAudio(result);
                e.wrap("<audio  src=\"https://res.wx.qq.com/voice/getvoice\" controls style=\"display: inline\"></audio>".replace("https://res.wx.qq.com/voice/getvoice", result));//在div前添加html内容

            }
        }

        if (htmlBody.contains("<html>")) {
            return document.toString();
        } else {
            return document.select("body>*").toString();
        }
    }

    /**
     * 获取网页
     *
     * @param uri
     * @return
     * @throws IOException
     */
    private static String getPageString(String uri) throws IOException {
        String dataSrc = uri;
        //获取网页内容
        String jsonStr = Jsoup.connect(dataSrc).ignoreContentType(true).execute().body();
//        System.out.println("网页内容：" + jsonStr);  //指定编码打印网页内容

        return jsonStr;


//        URL u = new URL(dataSrc);
//        System.out.println("\n-----u-----\n" + u);
//
//        CloseableHttpClient httpClient = HttpClients.createDefault();//创建HttpClient实例
//        HttpGet httpGet = new HttpGet(dataSrc);
//
////        //代理对象
////        HttpHost proxy = new HttpHost("127.0.0.1", 8888, "http");
////        //配置对象
////        RequestConfig config = RequestConfig.custom().setProxy(proxy).build();
////        //使用配置
////        httpGet.setConfig(config);
//        //设置请求头
////        httpGet.setHeader("Accept", "*/*");
////        httpGet.setHeader("Connection", "close");
////        httpGet.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
////        httpGet.setHeader("Accept-Encoding", "gzip, deflate");
////        httpGet.setHeader("Accept-Language", "zh-CN,zh;q=0.8");
////        httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36");
////        httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36");
//
//        CloseableHttpResponse response = httpClient.execute(httpGet);//执行get请求
//        HttpEntity entity = response.getEntity();//获取返回实体
//        String webContent = EntityUtils.toString(entity, "utf-8");
////        System.out.println("网页内容：" + webContent);  //指定编码打印网页内容
//
//        response.close();//关闭和释放系统资源
//
//        return webContent;
    }

    private static String getImg(String uri) {
        String dataSrc = uri;

        //创建保存路径
        String formatDate = DateUtil.getFormatDate("yyyy-MM-dd", DateUtil.getCurDate());
        String fileName = UUID.randomUUID().toString() + ".png";
        String dirName = SysConstant.OSS_FILE_DIR_PREFIX_WEB_SPIDER_IMG + formatDate + "/";

        //阿里云文件路径
        String webShowFilePath = SysConstant.OSS_ACCESS_PREFIX + dirName + fileName;
//        System.out.println("\n-----图片保存OSS路径-----\n" + webShowFilePath);

        //输入流
        File targetFile = null;
        BufferedImage bfImage = null;
        try {
            URL url = new URL(dataSrc);
            URLConnection conn = url.openConnection();
            InputStream inStream = conn.getInputStream();

            //临时文件
            targetFile = File.createTempFile(UUID.randomUUID().toString(), "img");
            java.nio.file.Files.copy(inStream, targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);


//            URL imgUrl = new URL(dataSrc);
//            bfImage = ImageIO.read(imgUrl);
//            //临时文件
//            targetFile = File.createTempFile(UUID.randomUUID().toString(), "img");
//            ImageIO.write(bfImage, "png", targetFile);

            AliyunOssClientUtil.uploadFileByLocalFile(targetFile, dirName + fileName);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //在JVM退出时删除临时文件。也可以调用file.delete();立即删除文件。
//            targetFile.deleteOnExit();
            //立即删除临时文件
            targetFile.delete();
        }

        return webShowFilePath;
    }

    //    private static String getVideo(String uri) throws IOException {
//        String dataSrc = uri;
//
//        //创建保存路径
//        String formatDate = DateUtil.getFormatDate("yyyy-MM-dd", DateUtil.getCurDate());
//        String fileName = UUID.randomUUID().toString() + ".mp4";
//        String dirName = SysConstant.OSS_FILE_DIR_PREFIX_WEB_SPIDER_TEST + formatDate + "/";
//
//        //阿里云文件路径
//        String webShowFilePath = SysConstant.OSS_ACCESS_PREFIX + dirName + fileName;
//        System.out.println("\n-----音频保存OSS路径-----\n" + webShowFilePath);
//
//        //获取视频输入流
//        File targetFile = null;
//        try {
//            HttpURLConnection webConn = null;
//            //获取视频链接
//            URL webUrl = new URL(dataSrc);
//            //打开链接
//            webConn = (HttpURLConnection) webUrl.openConnection();
//            //设置请求方式为"GET"
//            webConn.setRequestMethod("GET");
//            //建立连接的超时时间
//            webConn.setConnectTimeout(10 * 1000);
//            //传递数据的超时时间
//            webConn.setReadTimeout(10 * 1000);
//            //通过输入流获取图片数据
//            InputStream inStream = webConn.getInputStream();
//
//            //创建视频临时文件
//            targetFile = File.createTempFile(UUID.randomUUID().toString(), "video");
//            java.nio.file.Files.copy(inStream, targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
//
//            //上传操作
//            AliyunOssClientUtil.uploadFileByLocalFile(targetFile, dirName + fileName);
//
////                //从阿里云获取视频封面图
////                String imageUrl = webShowPath + "?x-oss-process=video/snapshot,t_1000,m_fast";
////
////                //视频封面图输入流
////                File targetFileImg = null;
////                BufferedImage bfImage = null;
////                try {
////                    URL imgUrl = new URL(imageUrl);
////                    bfImage = ImageIO.read(imgUrl);
////                    //视频封面图临时文件
////                    targetFileImg = File.createTempFile(UUID.randomUUID().toString(), "img");
////                    ImageIO.write(bfImage, "png", targetFileImg);
////
////                    String newFileName = fileName.replace(".mp4", ".png");
////                    AliyunOssClientUtil.uploadFileByLocalFile(targetFileImg, dirName + newFileName);
////
////                    //阿里云视频封面图路径
////                    String webShowImgPath = SysConstant.OSS_ACCESS_PREFIX + dirName + newFileName;
////                    System.out.println("\n-----视频封面图保存OSS路径-----\n" + webShowImgPath);
////                } catch (IOException e) {
////                    e.printStackTrace();
////                } finally {
////                    //在JVM退出时删除视频封面图临时文件。也可以调用file.delete();立即删除文件。
////                    targetFileImg.deleteOnExit();
////                    //立即删除视频封面图临时文件
////                    targetFileImg.delete();
////                }
//
//        } catch (Exception e) {
//            e.printStackTrace();
//        } finally {
//            //在JVM退出时删除视频封面图临时文件。也可以调用file.delete();立即删除文件。
//            targetFile.deleteOnExit();
//            //立即删除临时视频封面图临时文件
//            targetFile.delete();
//        }
//
//        return webShowPath;
//    }

    private static String getVideo(String uri) {
        String dataSrc = uri;

        //创建保存路径
        String formatDate = DateUtil.getFormatDate("yyyy-MM-dd", DateUtil.getCurDate());
        String fileName = UUID.randomUUID().toString() + ".mp4";
        String dirName = SysConstant.OSS_FILE_DIR_PREFIX_WEB_SPIDER_VIDEO + formatDate + "/";

        //阿里云文件路径
        String webShowFilePath = SysConstant.OSS_ACCESS_PREFIX + dirName + fileName;
//        System.out.println("\n-----视频保存OSS路径-----\n" + webShowFilePath);

        //输入流
        File targetFile = null;
        try {
            URL url = new URL(dataSrc);
            URLConnection conn = url.openConnection();
            InputStream inStream = conn.getInputStream();

            //临时文件
            targetFile = File.createTempFile(UUID.randomUUID().toString(), "video");
            java.nio.file.Files.copy(inStream, targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);

            AliyunOssClientUtil.uploadFileByLocalFile(targetFile, dirName + fileName);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //在JVM退出时删除临时文件。也可以调用file.delete();立即删除文件。
//            targetFile.deleteOnExit();
            //立即删除临时文件
            targetFile.delete();
        }

        return webShowFilePath;
    }

    private static String getAudio(String uri) {
        String dataSrc = uri;

        //创建保存路径
        String formatDate = DateUtil.getFormatDate("yyyy-MM-dd", DateUtil.getCurDate());
        String fileName = UUID.randomUUID().toString() + ".mp3";
        String dirName = SysConstant.OSS_FILE_DIR_PREFIX_WEB_SPIDER_AUDIO + formatDate + "/";

        //阿里云文件路径
        String webShowFilePath = SysConstant.OSS_ACCESS_PREFIX + dirName + fileName;
//        System.out.println("\n-----音频保存OSS路径-----\n" + webShowFilePath);

        //输入流
        File targetFile = null;
        try {
            URL url = new URL(dataSrc);
            URLConnection conn = url.openConnection();
            InputStream inStream = conn.getInputStream();

            //临时文件
            targetFile = File.createTempFile(UUID.randomUUID().toString(), "audio");
            java.nio.file.Files.copy(inStream, targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);

            AliyunOssClientUtil.uploadFileByLocalFile(targetFile, dirName + fileName);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //在JVM退出时删除临时文件。也可以调用file.delete();立即删除文件。
//            targetFile.deleteOnExit();
            //立即删除临时文件
            targetFile.delete();
        }

        return webShowFilePath;
    }

    /**
     * 将htmlBody中所有img标签中的src内容替换为原data-src的内容,
     * <br/>如果不报含data-src,则src的内容不会被替换
     * <br/>例如:
     * <br/> 替换前 &lt;img data-src="weixinImgUrl" src="localImgUrl" othreAttr="其他属性不变"/&gt;
     * <br/> 替换后 &lt;img src="weixinImgUrl" othreAttr="其他属性不变" /&gt;
     *
     * @param htmlBody
     * @return 返回替换后的内容
     */
    private static String replaceImgSrcFromDataSrc(String htmlBody) {
        Document document = Jsoup.parseBodyFragment(htmlBody);

        Elements nodes = document.select("img");
        int nodeLength = nodes.size();
        for (int i = 0; i < nodeLength; i++) {
            Element e = nodes.get(i);
            String dataSrc = e.attr("data-src");
            if (StringUtils.isNotBlank(dataSrc)) {
                //替换图片为自己的
                e.attr("src", getImg(dataSrc));
                e.removeAttr("data-src");
            }
        }

        if (htmlBody.contains("<html>")) {
            return document.toString();
        } else {
            return document.select("body>*").toString();
        }
    }

    /**
     * 根据url生成File
     */
    private static InputStream getFileByUrl(String webUrl, File resultFile) {
//        System.out.println("下载文件的uri：" + webUrl);
        InputStream test = null;

        HttpURLConnection conn = null;
        InputStream inStream = null;
        FileOutputStream outStream = null;
        try {
            URL url = new URL(webUrl);
            //打开链接
            conn = (HttpURLConnection) url.openConnection();
            //设置请求方式为"GET"
            conn.setRequestMethod("GET");
            //建立连接的超时时间
            conn.setConnectTimeout(10 * 1000);
            //传递数据的超时时间
            conn.setReadTimeout(10 * 1000);
            //通过输入流获取图片数据
            inStream = conn.getInputStream();
            test = inStream;

            //创建输出流
            outStream = new FileOutputStream(resultFile);
            byte[] buffer = new byte[1024];
            //每次读取的字符串长度，如果为-1，代表全部读取完毕
            int len;
            //使用一个输入流从buffer里把数据读取出来
            while ((len = inStream.read(buffer)) != -1) {
                //用输出流往buffer里写入数据，中间参数代表从哪个位置开始读，len代表读取的长度
                outStream.write(buffer, 0, len);
            }

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inStream != null) {
                try {
                    inStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (conn != null) {
                conn.disconnect();
            }

            if (outStream != null) {
                try {
                    outStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return test;
    }
}
